.TH msh 1
'''
.SH NAME
\fBmsh\fR \- mini-shell, process setup tool and batch command runner
'''
.SH SYNOPSIS
\fBmsh\fR \fIscript\fR \fIarguments\fR ...
.br
\fBmsh -c\fR \fIcommands\fR \fIarguments\fR ...
'''
.SH DESCRIPTION
\fBmsh\fR is a non-interactive command interpreter intended mostly for setting
up process environment for other applications, and running simple non-branching
command sequences. It is meant to be used in place of (much larger) POSIX shell
for system and service startup scripts that make no use of advanced scripting
features but could benefit from smaller interpreter and specific builtins.
'''
.SH EXAMPLE
.nf
#!/bin/msh

# Variable assignment
set VAR "some value"

# Running commands
run /sbin/kmod e1000e
echo "Module loaded"

# Variable substitution
echo $VAR

# Built-ins
exec /sbin/init
.fi
'''
.SH BUILTINS
These commands are run in the context of the shell process.
'''
.IP "\fBcd\fR \fIdirectory\fR" 4
See \fBchdir\fR(2).
.IP "\fBecho\fR \fImessage\fR" 4
Write \fImessage\fR to stdout.
.IP "\fBwarn\fR \fImessage\fR" 4
Same, to stderr.
.IP "\fBsleep\fR \fIseconds\fR" 4
See \fBnanosleep\fR(2). Fractional values are supported.
.IP "\fBwaitfor\fR \fIfile\fR [\fIseconds\fR]" 4
Wait until \fIfile\fR appears.
.IP "\fBexit\fR [\fIcode\fR]" 4
Terminate current process.
.IP "\fBexec\fR \fI/path/to/executable\fR \fIarg\fR \fIarg\fR ..." 4
Replace current process with \fIcommand\fR. See \fBexecve\fR(2).
.IP "\fBinvoke\fR \fI/path/to/executable\fR \fIarg\fR \fIarg\fR ..." 4
Do like \fBexec\fR but also append arguments passed to \fBmsh\fR itself.
.IP "\fBrun\fR \fI/path/to/executable\fR \fIarg\fR \fIarg\fR ..." 4
Spawn \fIcommand\fR and wait for it to complete. See \fBfork\fR(2),
\fBwaitpid\fR(2).
.IP "\fBonexit\fR \fI/path/to/executable\fR" 4
Instruct msh to exec into \fIexecutable\fR instead of exiting on error
on at the end of script.
.IP "\fBstdin\fR \fIfile\fR" 4
.IP "\fBstdout\fR [\fB-ax\fR] \fIfile\fR" 4
.IP "\fBstderr\fR [\fB-ax\fR] \fIfile\fR" 4
.IP "\fBstdtwo\fR [\fB-ax\fR] \fIfile\fR" 4
Redirect respective fds to the given \fIfile\fR; \fBstdtwo\fR redirects
both stdout and stderr. Options: \fBa\fRppend, open e\fBx\fRclusively (O_EXCL).
.IP "\fBreopen\fR \fIdevice\fR" 4
Redirect all three standard descriptors to \fIdevice\fR.
.IP "\fBclose\fR \fIfd\fR" 4
.IP "\fBdupfd\fR \fIold\fR \fInew\fR" 4
See \fBdup2\fR(2).
.IP "\fBwrite\fR \fIstring\fR \fIfile\fR" 4
For small writes to /sys and similar files.
.IP "\fBchroot\fR \fIdirectory\fR" 4
Change root.
.IP "\fBmkdir\fR \fIdirectory\fR [\fImode\fR [\fIuser\fB:\fIgroup\fR]]" 4
Create directory and chown it if necessary.
.IP "\fBumask\fR \fIvalue\fR" 4
Set umask for current process and all its children.
.IP "\fBsetuid\fR \fIid\fR" 4
Set real, effective and saved user ids to those of \fIuser\fR.
.IP "\fBsetgid\fR \fIid\fR" 4
Same with group ids.
.IP "\fBgroups\fR \fIid\fR \fIid\fR ..." 4
See \fBsetgroups\fR(2).
.IP "\fBscheduler\fR \fItype\fR [\fIpriority\fR]" 4
See \fBsched_setscheduler\fR(2); \fItype\fR should be one of "normal",
"fifo", "rr", "batch", "idle", \fIpriority\fR is 0 if omitted.
.IP "\fBsetcpus\fR \fIn n n\fR ..." 4
See \fBsched_setaffinity\fR(2). CPUs are numbered starting from 0.
.IP "\fBsetprio\fR \fInumber\fR" 4
See \fBsetpriority\fR(2). The argument is in Linux units, 1-40.
.IP "\fBrlimit\fR \fIkey\fR \fIcur\fR [\fImax\fR]" 4
See \fBprlimit\fR(2). \fIKey\fR for RLIMIT_CPU is just \fBcpu\fR.
.IP "\fBprctl seccomp\fR \fIfile\fR" 4
See \fBseccomp\fR(2), SECCOMP_SET_MODE_FILTER. The \fIfile\fR
is expected to contain compiled BPF opcodes.
.IP "\fBprctl secbits\fR \fIkey\fR \fIkey\fR ..." 4
See \fBcapabilities\fR(7) section "The securebits flags".
Possible \fIkey\fRs: \fBkeepcaps\fR, \fBnosetuid\fR, \fBnoroot\fR,
\fBnoraise\fR. Add \fB-lock\fR suffix to lock the bit.
.IP "\fBprctl no-new-privs\fR" 4
See \fBprctl\fR(2), PR_SET_NO_NEW_PRIVS.
.IP "\fBsetcaps\fR [\fB-peiab\fR] \fIkey\fR \fIkey\fR ..." 4
See \fBcapabilities\fR(7). \fIKey\fR for CAP_DAC_OVERRIDE is
\fBdac-override\fR. Options: \fBp\fRermitted, \fBe\fRffective,
\fBi\fRnheritable, \fBa\fRmbient, \fBb\fRounding. Default is \fB-peiab\fR.
.IP "\fBset\fR \fIvariable\fR \fIvalue\fR" 4
Define script-local variable; subsequent \fI$variable\fR references would
be substitued with \fIvalue\fR.
.IP "\fBsetenv\fR \fIvariable\fR \fIvalue\fR" 4
Set environment (envp) variable to a given value.
.IP "\fBgetenv\fR \fIvariable\fR" 4
Import named \fIvariable\fR from envp[] into script-local scope.
.IP "\fBdelenv\fR \fIvariable\fR" 4
Remove named variable from envp[].
.IP "\fBclearenv\fR" 4
Remove all variables from envp[].
'''
.SH NOTES
\fBmsh\fR is not a POSIX shell, and does a lot of things differently.
.P
Common POSIX shell features not supported in msh: redirections (>file),
pipes (|cmd), globbing (*), background execution (&), jobs, control flow
(while, case), advanced variable substituion (${var...}), backticks.
.P
\fBmsh\fR does not use PATH to locate executables.
.P
Like \fBmake\fR but unlike the POSIX shell, msh aborts on the first failed
command by default.
.P
Variable references ($var) in msh are always treated as a single token
regardless of the stored value, more like "$var" works in POSIX shell.
Example: `ls $dir` will always run ls with a single argument, even if
$dir is an empty string, or a string with spaces.
'''
.SS Capabilities, security bits and uid changes
To run a process with non-priviledged uid but with some capabilities set,
use the following sequence:
.P
.nf
	\fBsecbits\fR keepcaps
	\fBsetuid\fR \fIuser\fR
	\fBsetcaps\fR \fIcap\fR \fIcap\fR ...
	\fBexec\fR \fIcommand\fR ...
.fi
.P
Capability-aware commands may need \fB-i\fR or \fB-ib\fR, possibly with
\fB-a\fR. Refer to \fBcapabilities\fR(7).
